#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
发票OCR与结构化数据提取API

这个模块提供了基于FastAPI的API，用于发票图像OCR识别和结构化数据提取。
先使用通用JSON提取，再根据发票提示词进行映射转换。
"""

import mimetypes
import os
import sys
import json
import base64
from typing import Dict, Any, Optional, List, Union
import time
import traceback
import unicodedata
from decimal import Decimal, ROUND_HALF_UP
import re

# 导入OpenAI相关依赖
import openai

# 导入FastAPI相关依赖
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from py_files.config import get_client
from py_files.invoice_prompt_ocr.get_file_type_prompt import get_file_type_mappings, get_two_stage_prompts, get_ocr_prompt

# 创建路由器
router_ocr_invoice_prompt = APIRouter(
    prefix="/api/invoice_modle_prompt",
    tags=["发票OCR提示词处理"],
    responses={404: {"description": "未找到"}},
)

# 对外导出别名，确保其他模块可以正确导入
ocr_invoice_prompt = router_ocr_invoice_prompt

# 导出模块变量，以便在其他模块中导入使用
__all__ = ["router_ocr_invoice_prompt", "ocr_invoice_prompt"]

# 模型定义
class InvoiceExtractRequest(BaseModel):
    """发票数据提取请求模型"""
    image_file_path: str = Field(..., description="图像文件路径")
    model_name: Optional[str] = Field(None, description="要使用的模型名称，不指定则使用默认模型。对于多模态任务，建议使用带vl或flash的模型")
    file_type: Optional[str] = Field("发票", description="文件类型，默认为'发票'")

# API响应模型
class InvoiceExtractResponse(BaseModel):
    """发票数据提取响应模型"""
    status: str = Field(..., description="请求状态，如success或error")
    data: Dict[str, Any] = Field(..., description="提取的结构化数据")
    original_json: Optional[Dict[str, Any]] = Field(None, description="原始通用JSON数据")
    message: Optional[str] = Field(None, description="附加消息或错误信息")

def get_image_base64(image_path: str) -> str:
    """
    读取图像文件并转换为base64编码
    
    Args:
        image_path: 图像文件路径
        
    Returns:
        base64编码的图像字符串
    """
    try:
        with open(image_path, "rb") as image_file:
            encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
            return encoded_string
    except Exception as e:
        print(f"读取图像文件出错: {str(e)}")
        traceback.print_exc()
        raise

def image_to_data_url(file_path):
    """
    将图像文件转换为data URL格式
    
    Args:
        file_path: 图像文件路径
        
    Returns:
        data URL格式的图像字符串
    """
    # 获取文件的 MIME 类型（根据扩展名）
    mime_type, _ = mimetypes.guess_type(file_path)
    if not mime_type or not mime_type.startswith('image/'):
        mime_type = 'image/jpeg'  # 默认使用jpeg类型

    # 读取文件并编码为 Base64
    with open(file_path, "rb") as image_file:
        base64_data = base64.b64encode(image_file.read()).decode("utf-8")

    # 返回完整的data URL字符串
    return f"data:{mime_type};base64,{base64_data}"

def extract_general_json_from_image(image_path: str, model_key: str = None) -> Dict[str, Any]:
    """
    从图像中提取通用JSON数据
    
    Args:
        image_path: 图像文件路径
        model_key: 模型名称，默认为None时会使用配置中默认模型
        
    Returns:
        包含JSON数据和OCR文本的字典: {'json_data': {...}, 'ocr_text': '...'}
    """
    print(f"开始从图像提取通用JSON数据...")
    try:
        # 读取图像文件
        data_url = image_to_data_url(image_path)
        # 获取OCR提示词
        ocr_prompt = get_ocr_prompt()
        
        # 调用模型进行OCR识别 - 复用这个结果作为OCR文本
        client, model_name = get_client(model_key)
        
        # 准备带图像的OCR消息
        ocr_request_messages = [
            {"role": "system", "content": "你是一个专业的OCR文本识别助手，请从图片中提取所有可见的文字内容，保持原始布局。"},
            {"role": "user", "content": [
                {"type": "text", "text": ocr_prompt},
                {"type": "image_url", "image_url": data_url}
            ]}
        ]
        
        # 发送OCR请求
        ocr_response = client.chat.completions.create(
            model=model_name,
            messages=ocr_request_messages,
            max_tokens=3000,
            temperature=0.2
        )
        
        # 获取OCR文本结果
        ocr_text = ocr_response.choices[0].message.content
        print(f"OCR识别结果 (部分显示): {ocr_text[:200]}...")
        
        # 获取通用JSON提取提示词
        file_type_mappings = get_file_type_mappings()
        general_json_prompt = file_type_mappings.get("通用json", {}).get("prompt", "")
        
        if not general_json_prompt:
            raise ValueError("未找到通用JSON提取提示词")
        
        # 准备带图像的JSON提取消息
        json_request_messages = [
            {"role": "system", "content": "你是一个专业的结构化数据提取助手，能够从图片中提取关键信息并转换为JSON格式。"},
            {"role": "user", "content": [
                {"type": "text", "text": general_json_prompt},
                {"type": "image_url", "image_url": data_url}
            ]}
        ]
        
        # 发送JSON提取请求
        json_response = client.chat.completions.create(
            model=model_name,
            messages=json_request_messages,
            max_tokens=3000,
            temperature=0.2
        )
        
        # 获取原始响应内容
        content = json_response.choices[0].message.content
        print(f"通用JSON提取结果 (部分显示): {content[:200]}...")
        
        # 尝试从内容中提取JSON数据
        json_data = extract_json_from_content(content)
        
        # 返回结构化的结果，同时包含JSON数据和OCR文本
        return {
            "json_data": json_data,
            "ocr_text": ocr_text
        }
    except Exception as e:
        print(f"从图像提取通用JSON数据出错: {str(e)}")
        traceback.print_exc()
        raise

def extract_json_from_content(content: str) -> Dict[str, Any]:
    """
    从模型返回的内容中安全提取JSON
    
    Args:
        content: 模型返回的文本内容
        
    Returns:
        提取的JSON数据，如果解析失败则返回原始内容
    """
    # 保存原始内容
    result = {"raw_content": content}
    
    try:
        # 检查是否包含JSON代码块
        if "```json" in content:
            # 提取```json和```之间的内容
            json_content = content.split("```json")[1].split("```")[0].strip()
        elif "```" in content:
            # 提取```和```之间的内容
            json_content = content.split("```")[1].split("```")[0].strip()
        else:
            # 假设整个内容是JSON
            json_content = content.strip()
            
        # 处理可能的单引号问题
        if "'" in json_content and '"' not in json_content:
            json_content = json_content.replace("'", '"')
            
        # 尝试解析JSON
        parsed_json = json.loads(json_content)
        
        # 如果成功解析，添加到结果中
        result["parsed_json"] = parsed_json
        
        # 处理可能的嵌套结构，如json_result
        if isinstance(parsed_json, dict) and "json_result" in parsed_json:
            result["parsed_json"] = parsed_json["json_result"]
    except Exception as e:
        # 如果解析失败，记录错误但不抛出异常
        print(f"JSON解析失败: {str(e)}")
        result["parse_error"] = str(e)
    
    return result

def extract_ocr_text_from_image(image_path: str, model_key: str = None) -> str:
    """
    从图像中提取OCR文本 - 此函数保留但不再使用，已合并到extract_general_json_from_image
    
    Args:
        image_path: 图像文件路径
        model_key: 模型名称，默认为None时会使用配置中默认模型
        
    Returns:
        提取的OCR文本
    """
    print(f"开始从图像提取OCR文本...")
    try:
        # 读取图像文件
        data_url = image_to_data_url(image_path)
        # 获取OCR提示词
        ocr_prompt = get_ocr_prompt()
        
        # 调用模型进行OCR识别
        client, model_name = get_client(model_key)
        
        # 准备带图像的消息
        ocr_request_messages = [
            {"role": "system", "content": "你是一个专业的OCR文本识别助手，请从图片中提取所有可见的文字内容，保持原始布局。"},
            {"role": "user", "content": [
                {"type": "text", "text": ocr_prompt},
                {"type": "image_url", "image_url": data_url}
            ]}
        ]
        
        # 发送OCR请求
        ocr_response = client.chat.completions.create(
            model=model_name,
            messages=ocr_request_messages,
            max_tokens=3000,
            temperature=0.2
        )
        
        # 获取OCR文本结果
        ocr_text = ocr_response.choices[0].message.content
        print(f"OCR识别结果 (部分显示): {ocr_text[:200]}...")
        
        return ocr_text
    except Exception as e:
        print(f"从图像提取OCR文本出错: {str(e)}")
        traceback.print_exc()
        raise

def map_to_invoice_structure(ocr_text: str, model_key: str = None, file_type: str = "发票") -> Dict[str, Any]:
    """
    将OCR文本映射到发票结构
    
    Args:
        ocr_text: OCR识别的文本
        model_key: 模型名称，默认为None时会使用配置中默认模型
        file_type: 文件类型，默认为"发票"
        
    Returns:
        映射后的发票结构化数据
    """
    print(f"开始将OCR文本映射到{file_type}结构...")
    try:
        # 获取两阶段提示词
        system_prompt, user_prompt = get_two_stage_prompts(file_type, ocr_text)
        
        # 调用模型进行结构化映射
        client, model_name = get_client(model_key)
        
        # 准备消息
        mapping_request_messages = [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_prompt}
        ]
        
        # 发送映射请求
        mapping_response = client.chat.completions.create(
            model=model_name,
            messages=mapping_request_messages,
            max_tokens=3000,
            temperature=0.2
        )
        
        # 获取映射结果
        content = mapping_response.choices[0].message.content
        print(f"映射结果 (部分显示): {content[:200]}...")
        
        # 处理JSON内容
        if "```json" in content:
            # 提取```json和```之间的内容
            json_content = content.split("```json")[1].split("```")[0].strip()
        elif "```" in content:
            # 提取```和```之间的内容
            json_content = content.split("```")[1].split("```")[0].strip()
        else:
            json_content = content.strip()
        
        # 处理可能的单引号问题
        if json_content.startswith("'") or json_content.startswith("{"):
            json_content = json_content.replace("'", "\"")
        
        # 解析JSON
        result = json.loads(json_content)
        
        return result
    except Exception as e:
        print(f"OCR文本映射到{file_type}结构出错: {str(e)}")
        traceback.print_exc()
        raise

def clean_invoice_data(invoice_data: Dict[str, Any]) -> Dict[str, Any]:
    """
    清理发票数据中的数量和金额相关字段的特殊符号
    
    Args:
        invoice_data: 提取的发票数据
        
    Returns:
        清理后的发票数据
    """
    # print("清理发票数据中的数量和金额字段的特殊符号...")
    
    # 定义需要清理特殊符号的金额和数量相关字段
    amount_fields = [
        "number", "unitPrice", "totalPrice", "taxAmount", 
        "totalAmount", "totalTax", "totalSmall"
    ]
    
    # 创建一个新的字典来存储清理后的数据
    cleaned_data = invoice_data.copy()
    
    # 常见的货币符号和单位
    currency_symbols = ['¥', '$', '€', '£', '₹', '₽', '元', '圆', '万元', '万', '亿', '亿元', '角', '分', 'RMB', 'CNY', 'USD', 'EUR']
    
    # 清理所有金额和数量字段
    for field in amount_fields:
        if field in cleaned_data and cleaned_data[field]:
            # 先检查字段值是否为字符串
            if isinstance(cleaned_data[field], str):
                # 移除常见货币符号和单位
                value = cleaned_data[field]
                for symbol in currency_symbols:
                    value = value.replace(symbol, '')
                
                # 只保留数字、小数点和逗号
                # 对于金额字段，我们只需要保留数字和小数点，不需要任何特殊符号
                if field != "totalBig":  # 不处理大写金额字段
                    value = ''.join(c for c in value if c.isdigit() or c == '.' or c == ',')
                    
                # 去除前后空格
                value = value.strip()
                
                # 如果结果不为空，更新字段值
                if value:
                    cleaned_data[field] = value
    
    # 特殊处理model(规格型号)字段，保留特殊符号但纠正常见错误
    if "model" in cleaned_data and cleaned_data["model"]:
        if isinstance(cleaned_data["model"], str):
            model_value = cleaned_data["model"]
            
            # 定义需要进行正则表达式处理的模式
            regex_patterns = [
                (r'(^|[^A-Za-z0-9])(中)([0-9]+)', r'\1Φ\3'),  # "中80" -> "Φ80"
                (r'(^|[^A-Za-z0-9])(口)([0-9]+)', r'\1□\3'),  # "口60" -> "□60"
                (r'(^|[^A-Za-z0-9])(田)([0-9]+)', r'\1□\3'),  # "田20" -> "□20"
                (r'(^|[^A-Za-z0-9])(日)O', r'\1B0'),          # "日O" -> "B0"
                (r'(^|[^A-Za-z0-9])l([0-9])', r'\11\2'),     # "l2" -> "12"
                (r'([0-9])O', r'\10'),                        # "5O" -> "50"
                (r'([0-9])o', r'\10'),                        # "5o" -> "50"
                (r'([A-Za-z])-([0-9])', r'\1\2'),             # "A-8" -> "A8" (常见的OCR分割错误)
                (r'([0-9])-([A-Za-z])', r'\1\2'),             # "8-B" -> "8B" (常见的OCR分割错误)
            ]
            
            # 应用所有正则表达式模式
            for pattern, replacement in regex_patterns:
                model_value = re.sub(pattern, replacement, model_value)
            
            # 预定义的替换规则，用于矫正可能的OCR错误
            model_replacements = {
                "口": "□",     # 修正方框符号
                "日O": "B0",   # 常见错误模式
                "曰": "日",     # 修正特殊符号
                "囗": "□",     # 修正方框符号
                "田": "□",     # 修正方框符号
                "中数": "Φ",    # 错误识别直径符号
                "中": "Φ",      # 中字可能是直径符号
                "5O": "50",    # 数字5与字母O的组合
                "l0": "10",    # 小写字母l与数字0的组合
                "l1": "11",    # 小写字母l与数字1的组合
                "l2": "12",    # 小写字母l与数字2的组合
                "l3": "13",    # 小写字母l与数字3的组合
                "I0": "10",    # 大写字母I与数字0的组合
                "I1": "11",    # 大写字母I与数字1的组合
                "I2": "12",    # 大写字母I与数字2的组合
                "I3": "13",    # 大写字母I与数字3的组合
                "O0": "00",    # 字母O与数字0的组合
                "O1": "01",    # 字母O与数字1的组合
                "O2": "02",    # 字母O与数字2的组合
                "o0": "00",    # 小写字母o与数字0的组合
                "o1": "01",    # 小写字母o与数字1的组合
                "o2": "02",    # 小写字母o与数字2的组合
                "米": "㎡",     # 修正面积单位符号
                "圆": "○",     # 修正圆圈符号
                "加": "+",     # 修正加号
                "减": "-",     # 修正减号
                "乘": "×",     # 修正乘号
                "除": "÷",     # 修正除号
                "等": "=",     # 修正等号
                "星": "*",     # 修正星号
                "角": "∠",     # 修正角度符号
                "度": "°",     # 修正度数符号
                "井": "#",     # 修正井号
                "点": ".",     # 修正点号
                "横": "-",     # 修正横线
                "斜": "/",     # 修正斜线
                "括": "()",    # 修正括号
                "冒": ":",     # 修正冒号
                "逗": ",",     # 修正逗号
                "甲": "A",     # 修正甲乙丙丁
                "乙": "B",     # 修正甲乙丙丁
                "丙": "C",     # 修正甲乙丙丁
                "丁": "D",     # 修正甲乙丙丁
            }
            
            # 应用所有替换规则
            for wrong, correct in model_replacements.items():
                model_value = model_value.replace(wrong, correct)
            
            # 处理model字段中的特殊字符
            processed_model = ""
            for char in model_value:
                # 保留数字、字母、中文和特殊符号
                if char.isdigit() or char.isalpha() or '\u4e00' <= char <= '\u9fff' or is_special_char(char):
                    processed_model += char
            
            # 进行最终的字符级替换
            processed_model = processed_model.replace("l", "1")  # 小写l替换为数字1
            processed_model = processed_model.replace("O", "0")  # 大写O替换为数字0
            processed_model = processed_model.replace("o", "0")  # 小写o替换为数字0
            processed_model = processed_model.replace("I", "1")  # 大写I替换为数字1
            
            # 去除前后空格
            processed_model = processed_model.strip()
            
            # 如果结果不为空，更新字段值
            if processed_model:
                cleaned_data["model"] = processed_model
    
    return cleaned_data

def validate_invoice_data(invoice_data: Dict[str, Any]) -> bool:
    """
    验证发票数据中的数字字段
    
    Args:
        invoice_data: 提取的发票数据
        
    Returns:
        验证结果，True表示验证通过，False表示验证失败
    """
    print("验证发票数据中的数字字段...")
    
    # 定义需要验证的金额和数量相关字段
    amount_fields = [
        "number", "unitPrice", "totalPrice", "taxAmount", 
        "totalAmount", "totalTax", "totalSmall"
    ]
    
    # 验证所有金额和数量字段
    for field in amount_fields:
        if field in invoice_data and invoice_data[field]:
            # 检查字段值是否为数字
            if not isinstance(invoice_data[field], (int, float, Decimal)):
                print(f"验证失败: {field} 不是数字类型")
                return False
            
            # 检查字段值是否为正数
            if isinstance(invoice_data[field], (int, float)):
                if invoice_data[field] <= 0:
                    print(f"验证失败: {field} 不是正数")
                    return False
            elif isinstance(invoice_data[field], Decimal):
                if invoice_data[field] <= Decimal('0'):
                    print(f"验证失败: {field} 不是正数")
                    return False
    
    return True

def normalize_number(value_str: str) -> Optional[Decimal]:
    """
    将字符串格式的数字转换为Decimal类型
    
    Args:
        value_str: 数字字符串
        
    Returns:
        转换后的Decimal数字，无法转换则返回None
    """
    if not value_str or not isinstance(value_str, str):
        return None
    
    # 移除逗号和空格
    value_str = value_str.replace(',', '').replace(' ', '')
    
    # 如果是空字符串，返回None
    if not value_str:
        return None
    
    try:
        # 尝试转换为Decimal
        return Decimal(value_str)
    except:
        return None

def format_decimal(value: Decimal) -> str:
    """
    格式化Decimal数字为字符串
    
    Args:
        value: Decimal数字
        
    Returns:
        格式化后的字符串
    """
    if value is None:
        return ''
    
    # 保留两位小数
    return str(value.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP))

def parse_tax_rate(tax_rate_str: str) -> Optional[Decimal]:
    """
    解析税率字符串为Decimal
    
    Args:
        tax_rate_str: 税率字符串，如'13%'
        
    Returns:
        解析后的税率，如0.13
    """
    if not tax_rate_str:
        return None
    
    # 移除百分号和空格
    tax_rate_str = tax_rate_str.replace('%', '').replace(' ', '')
    
    try:
        # 转换为Decimal并除以100
        return Decimal(tax_rate_str) / Decimal('100')
    except:
        return None

def split_with_special_chars(value: str, delimiter: str) -> List[str]:
    """
    使用指定的分隔符拆分字符串，处理特殊情况
    
    Args:
        value: 要拆分的字符串
        delimiter: 分隔符
        
    Returns:
        拆分后的字符串列表
    """
    if not value:
        return []
    
    return [item.strip() for item in value.split(delimiter) if item.strip()]

def sanitize_item_name(name: str) -> str:
    """
    清理商品名称中的特殊字符
    
    Args:
        name: 商品名称
        
    Returns:
        清理后的商品名称
    """
    return name.replace('*', '').strip()

def is_special_char(char: str) -> bool:
    """
    检查字符是否为特殊符号
    
    Args:
        char: 单个字符
    
    Returns:
        是否为特殊符号
    """
    # 定义常见特殊符号范围，特别包含产品规格型号中常见的符号
    special_chars = set('Φφ±%㎜㎝㎡¥$€£₹₽®©™#№§°×÷√πΩμαβγδ@&*~^•·※★☆◆◇■□▲△▼▽◉○●✓✔✕✖➤→←↑↓〒〃々〆〇〄㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉+-/:_()[]{}<>\\,.\'\"=|')
    
    # 可能被OCR错误识别为汉字的特殊字符映射
    # 例如，"中"可能是"Φ"，"田"可能是"□"等
    potential_misrecognized_chars = {
        '中': 'Φ',  # 中可能是Φ（希腊字母Phi）
        '田': '□',  # 田可能是方块符号
        '米': '㎡',  # 米可能是平方米符号
        '圆': '○',  # 圆可能是圆圈符号
        '加': '+',  # 加可能是加号
        '减': '-',  # 减可能是减号
        '乘': '×',  # 乘可能是乘号
        '除': '÷',  # 除可能是除号
        '等': '=',  # 等可能是等号
        '星': '*',  # 星可能是星号
        '角': '∠',  # 角可能是角度符号
        '度': '°',  # 度可能是度数符号
        '井': '#',  # 井可能是井号
        '点': '.',  # 点可能是点号
        '横': '-',  # 横可能是横线
        '斜': '/',  # 斜可能是斜线
        '括': '()',  # 括可能是括号
        '冒': ':',  # 冒可能是冒号
        '逗': ',',  # 逗可能是逗号
        '空': ' ',  # 空可能是空格
        '叁': '3',  # 叁可能是3
        '肆': '4',  # 肆可能是4
        '伍': '5',  # 伍可能是5
        '陆': '6',  # 陆可能是6
        '柒': '7',  # 柒可能是7
        '捌': '8',  # 捌可能是8
        '玖': '9',  # 玖可能是9
        '零': '0',  # 零可能是0
        '壹': '1',  # 壹可能是1
        '贰': '2',  # 贰可能是2
    }
    
    # 中文数字组合中可能的语义不匹配识别
    # 这些组合在规格型号中可能是有特殊含义的，但也可能是OCR错误
    semantic_mismatch_patterns = {
        '口': '□',  # "口"可能是方框符号
        '日': '曰',  # "日"可能是特殊符号
        '目': '□',  # "目"可能是方框符号
        '由': '甲',  # "由"可能是错误识别
        '甲': 'A',   # "甲"可能是A
        '乙': 'B',   # "乙"可能是B
        '丙': 'C',   # "丙"可能是C
        '丁': 'D',   # "丁"可能是D
        '戊': 'E',   # "戊"可能是E
        '己': 'F',   # "己"可能是F
        '庚': 'G',   # "庚"可能是G
        '辛': 'H',   # "辛"可能是H
        '壬': 'I',   # "壬"可能是I
        '癸': 'J',   # "癸"可能是J
    }
    
    # 补充更多可能的错误识别
    potential_misrecognized_chars.update(semantic_mismatch_patterns)
    
    # 检查是否是可能被误识别的汉字
    if char in potential_misrecognized_chars:
        return True
    
    # 检查是否在特殊符号集合中
    if char in special_chars:
        return True
    
    # 检查是否为空格
    if char.isspace():
        return True
    
    # 检查是否为其他Unicode特殊符号
    categories = ['Sm', 'Sc', 'So', 'Po', 'Pc', 'Pd', 'Ps', 'Pe', 'Pi', 'Pf']
    for cat in categories:
        if unicodedata.category(char).startswith(cat):
            return True
    
    return False

def validate_invoice_numbers(result: Dict[str, Any]) -> Dict[str, Any]:
    """
    验证发票中的数字字段，检查金额计算是否正确
    
    Args:
        result: 从OCR提取的发票信息字典
    
    Returns:
        包含验证结果的字典，无论是否验证成功都包含详细信息
    """
    validation_result = {
        "status": "all_valid",
        "details": {}
    }
    has_error = False
    
    # 获取各个字段的值
    try:
        # 检查是否有多项商品
        has_multiple_items = (',' in result.get('tradeName', '') or ';' in result.get('tradeName', ''))
        
        # 解析金额和税额
        total_price_str = result.get('totalPrice', '')
        total_tax_str = result.get('totalTax', '')
        total_amount_str = result.get('totalAmount', '')
        total_small_str = result.get('totalSmall', '')
        
        # 解析单项金额、数量、单价和税额 - 使用增强的分割函数处理特殊符号
        trade_names = split_with_special_chars(result.get('tradeName', ''), ';' if ';' in result.get('tradeName', '') else ',')
        if len(trade_names) == 1 and not has_multiple_items:
            trade_names = [result.get('tradeName', '')]
        
        numbers_str = result.get('number', '').split(',') if ',' in result.get('number', '') else [result.get('number', '')]
        unit_prices_str = result.get('unitPrice', '').split(',') if ',' in result.get('unitPrice', '') else [result.get('unitPrice', '')]
        prices_str = result.get('totalPrice', '').split(',') if ',' in result.get('totalPrice', '') else [result.get('totalPrice', '')]
        tax_amounts_str = result.get('taxAmount', '').split(',') if ',' in result.get('taxAmount', '') else [result.get('taxAmount', '')]
        tax_rates_str = result.get('taxRate', '').split(',') if ',' in result.get('taxRate', '') else [result.get('taxRate', '')]
        
        # 统一数组长度
        max_len = max(len(trade_names), len(numbers_str), len(unit_prices_str), len(prices_str), len(tax_amounts_str), len(tax_rates_str))
        trade_names = (trade_names + [''] * max_len)[:max_len]
        numbers_str = (numbers_str + [''] * max_len)[:max_len]
        unit_prices_str = (unit_prices_str + [''] * max_len)[:max_len]
        prices_str = (prices_str + [''] * max_len)[:max_len]
        tax_amounts_str = (tax_amounts_str + [''] * max_len)[:max_len]
        tax_rates_str = (tax_rates_str + [''] * max_len)[:max_len]
        
        # 处理商品名称中的特殊符号
        trade_names = [sanitize_item_name(name) for name in trade_names]
        
        # 检查规格型号(model)字段
        model_value = result.get('model', '')
        if model_value:
            # 定义正则表达式模式以检测可能的错误
            regex_patterns = [
                (r'(^|[^A-Za-z0-9])(中)([0-9]+)', r'\1Φ\3', "中字错误识别为直径符号Φ"),
                (r'(^|[^A-Za-z0-9])(口)([0-9]+)', r'\1□\3', "口字错误识别为方框符号□"),
                (r'(^|[^A-Za-z0-9])(田)([0-9]+)', r'\1□\3', "田字错误识别为方框符号□"),
                (r'(^|[^A-Za-z0-9])(日)O', r'\1B0', "日O字符组合错误识别为B0"),
                (r'(^|[^A-Za-z0-9])l([0-9])', r'\11\2', "小写字母l错误识别为数字1"),
                (r'([0-9])O', r'\10'),                        # "5O" -> "50"
                (r'([0-9])o', r'\10'),                        # "5o" -> "50"
                (r'([A-Za-z])-([0-9])', r'\1\2'),             # "A-8" -> "A8" (常见的OCR分割错误)
                (r'([0-9])-([A-Za-z])', r'\1\2'),             # "8-B" -> "8B" (常见的OCR分割错误)
            ]
            
            # 检查所有可能的替换模式
            suspicious_patterns = []
            corrected_model = model_value
            
            # 应用正则表达式检测和替换
            for pattern, replacement, message in regex_patterns:
                if re.search(pattern, corrected_model):
                    suspicious_patterns.append(message)
                    corrected_model = re.sub(pattern, replacement, corrected_model)
            
            # 字符级别的替换检测
            char_replacements = [
                ("口", "□", "方框符号"),
                ("日O", "B0", "常见型号错误"),
                ("曰", "日", "特殊符号"),
                ("囗", "□", "方框符号"),
                ("田", "□", "方框符号"),
                ("中", "Φ", "直径符号"),
                ("l", "1", "数字1"),
                ("O", "0", "数字0"),
                ("o", "0", "数字0"),
                ("I", "1", "数字1"),
                ("米", "㎡", "面积单位"),
                ("圆", "○", "圆形符号"),
                ("甲", "A", "拉丁字母A"),
                ("乙", "B", "拉丁字母B"),
                ("丙", "C", "拉丁字母C"),
                ("丁", "D", "拉丁字母D"),
            ]
            
            # 检查字符级替换
            for wrong, correct, desc in char_replacements:
                if wrong in corrected_model:
                    suspicious_patterns.append(f"'{wrong}'应为'{correct}'({desc})")
                    corrected_model = corrected_model.replace(wrong, correct)
            
            # 如果发现了可疑模式
            if suspicious_patterns:
                validation_result['details']['model'] = {
                    'extracted': model_value,
                    'corrected': corrected_model,
                    'status': 'warning',
                    'message': f"规格型号可能存在识别错误: {', '.join(suspicious_patterns)}",
                    'suggestion': '请确认规格型号是否正确修正'
                }
            else:
                validation_result['details']['model'] = {
                    'extracted': model_value,
                    'status': 'valid',
                    'message': '规格型号正常'
                }
        
        # 转换为Decimal进行精确计算
        numbers = [normalize_number(num.strip()) for num in numbers_str]
        unit_prices = [normalize_number(price.strip()) for price in unit_prices_str]
        prices = [normalize_number(price.strip()) for price in prices_str]
        tax_amounts = [normalize_number(tax.strip()) for tax in tax_amounts_str]
        tax_rates = [parse_tax_rate(rate.strip()) for rate in tax_rates_str]
        
        total_price = normalize_number(total_price_str)
        total_tax = normalize_number(total_tax_str)
        total_amount = normalize_number(total_amount_str)
        total_small = normalize_number(total_small_str)
        
        # 验证1: 检查各项金额之和是否等于总金额
        calculated_total_price = sum((p for p in prices if p is not None), Decimal('0'))
        if total_price is not None and calculated_total_price != Decimal('0'):
            if abs(calculated_total_price - total_price) > Decimal('0.01'):
                validation_result['details']['totalPrice'] = {
                    'extracted': total_price_str,
                    'calculated': format_decimal(calculated_total_price),
                    'error': '各项金额之和与总金额不匹配',
                    'status': 'error'
                }
                has_error = True
            else:
                validation_result['details']['totalPrice'] = {
                    'extracted': total_price_str,
                    'calculated': format_decimal(calculated_total_price),
                    'status': 'valid',
                    'message': '各项金额之和与总金额匹配'
                }
        
        # 验证2: 检查各项税额之和是否等于总税额
        calculated_total_tax = sum((t for t in tax_amounts if t is not None), Decimal('0'))
        if total_tax is not None and calculated_total_tax != Decimal('0'):
            if abs(calculated_total_tax - total_tax) > Decimal('0.01'):
                validation_result['details']['totalTax'] = {
                    'extracted': total_tax_str,
                    'calculated': format_decimal(calculated_total_tax),
                    'error': '各项税额之和与总税额不匹配',
                    'status': 'error'
                }
                has_error = True
            else:
                validation_result['details']['totalTax'] = {
                    'extracted': total_tax_str,
                    'calculated': format_decimal(calculated_total_tax),
                    'status': 'valid',
                    'message': '各项税额之和与总税额匹配'
                }
        
        # 验证3: 检查每项金额是否等于数量乘以单价
        for i in range(max_len):
            # 验证单个项目的金额计算
            if numbers[i] is not None and unit_prices[i] is not None and prices[i] is not None:
                calculated_price = (numbers[i] * unit_prices[i]).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
                field_key = f"amount_{i+1}" if max_len > 1 else "amount"
                
                if abs(calculated_price - prices[i]) > Decimal('0.01'):
                    validation_result['details'][field_key] = {
                        'extracted': prices_str[i],
                        'calculated': format_decimal(calculated_price),
                        'error': f'金额计算有误，应为 {numbers[i]} × {unit_prices[i]} = {calculated_price}',
                        'status': 'error',
                        'item': trade_names[i].strip()
                    }
                    has_error = True
                else:
                    validation_result['details'][field_key] = {
                        'extracted': prices_str[i],
                        'calculated': format_decimal(calculated_price),
                        'status': 'valid',
                        'message': '金额 = 数量 × 单价',
                        'item': trade_names[i].strip()
                    }
        
        # 验证4: 检查每项金额和税率计算的税额是否正确
        for i in range(max_len):
            if prices[i] is not None and tax_rates[i] is not None and tax_amounts[i] is not None:
                calculated_tax = (prices[i] * tax_rates[i]).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
                field_key = f"taxAmount_{i+1}" if max_len > 1 else "taxAmount"
                
                if abs(calculated_tax - tax_amounts[i]) > Decimal('0.01'):
                    validation_result['details'][field_key] = {
                        'extracted': tax_amounts_str[i],
                        'calculated': format_decimal(calculated_tax),
                        'error': f'税额计算有误，应为 {prices[i]} × {tax_rates[i]} = {calculated_tax}',
                        'status': 'error',
                        'item': trade_names[i].strip()
                    }
                    has_error = True
                else:
                    validation_result['details'][field_key] = {
                        'extracted': tax_amounts_str[i],
                        'calculated': format_decimal(calculated_tax),
                        'status': 'valid',
                        'message': '税额计算正确',
                        'item': trade_names[i].strip()
                    }
        
        # 验证5: 检查金额+税额是否等于价税合计
        if total_price is not None and total_tax is not None and total_small is not None:
            calculated_total = total_price + total_tax
            if abs(calculated_total - total_small) > Decimal('0.01'):
                validation_result['details']['totalSmall_check1'] = {
                    'extracted': total_small_str,
                    'calculated': format_decimal(calculated_total),
                    'error': f'价税合计不等于总金额({total_price_str})+总税额({total_tax_str})',
                    'status': 'error'
                }
                has_error = True
            else:
                validation_result['details']['totalSmall_check1'] = {
                    'extracted': total_small_str,
                    'calculated': format_decimal(calculated_total),
                    'status': 'valid',
                    'message': '价税合计等于总金额+总税额'
                }
                
            # 增加价税合计的中文大写验证
            total_big_str = result.get('totalBig', '')
            if total_big_str:
                # 添加对大写金额的验证（这里仅作简单验证）
                validation_result['details']['totalBig'] = {
                    'extracted': total_big_str,
                    'expected': '与价税合计对应的大写金额',
                    'status': 'info',
                    'message': '大写金额显示为：' + total_big_str
                }
        
        # 验证6: 检查totalAmount和totalPrice是否一致
        if total_amount is not None and total_price is not None:
            if abs(total_amount - total_price) > Decimal('0.01'):
                validation_result['details']['totalAmount'] = {
                    'extracted': total_amount_str,
                    'expected': total_price_str,
                    'error': 'totalAmount应与totalPrice一致',
                    'status': 'error'
                }
                has_error = True
            else:
                validation_result['details']['totalAmount'] = {
                    'extracted': total_amount_str,
                    'expected': total_price_str,
                    'status': 'valid',
                    'message': 'totalAmount与totalPrice一致'
                }
        
        # 验证7: 检查价税合计是否等于总额(totalAmount)+总税额(totalTax)
        if total_amount is not None and total_tax is not None and total_small is not None:
            calculated_total_small = total_amount + total_tax
            if abs(calculated_total_small - total_small) > Decimal('0.01'):
                validation_result['details']['totalSmall_check2'] = {
                    'extracted': total_small_str,
                    'calculated': format_decimal(calculated_total_small),
                    'error': f'价税合计不等于总额({total_amount_str})+总税额({total_tax_str})',
                    'status': 'error'
                }
                has_error = True
            else:
                validation_result['details']['totalSmall_check2'] = {
                    'extracted': total_small_str,
                    'calculated': format_decimal(calculated_total_small),
                    'status': 'valid',
                    'message': '价税合计等于总额+总税额'
                }
        
        # 验证8: 项目明细汇总验证
        if has_multiple_items and max_len > 1:
            items_summary = []
            for i in range(max_len):
                if trade_names[i]:
                    item_data = {
                        'tradeName': trade_names[i].strip(),
                        'number': numbers_str[i],
                        'unitPrice': unit_prices_str[i],
                        'amount': prices_str[i],
                        'taxRate': tax_rates_str[i],
                        'taxAmount': tax_amounts_str[i]
                    }
                    items_summary.append(item_data)
            
            validation_result['details']['items_summary'] = {
                'status': 'info',
                'message': f'发票包含{len(items_summary)}个商品项目',
                'items': items_summary
            }
        
        # 更新整体验证状态
        if has_error:
            validation_result['status'] = 'has_errors'
    
    except Exception as e:
        validation_result['status'] = 'validation_error'
        validation_result['error'] = f"验证过程发生错误: {str(e)}"
        validation_result['traceback'] = traceback.format_exc()
        
    return validation_result

@router_ocr_invoice_prompt.post("/extract", response_model=InvoiceExtractResponse)
async def extract_invoice_data(request: InvoiceExtractRequest) -> Dict[str, Any]:
    """
    从图像文件中提取发票数据
    
    Args:
        request: 请求对象，包含image_file_path、model_name和file_type
    
    Returns:
        提取的发票数据，包含status、data和message字段
    """
    try:
        # 检查文件是否存在
        image_path = request.image_file_path
        # 替换路径中可能的斜杠问题
        image_path = image_path.replace('\\', '/')
        
        if not os.path.exists(image_path):
            # 尝试查找相对路径
            base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
            alternative_path = os.path.join(base_dir, image_path)
            if os.path.exists(alternative_path):
                image_path = alternative_path
            else:
                return {
                    "status": "error",
                    "message": f"文件不存在: {image_path}，请检查路径是否正确",
                    "data": {},
                    "original_json": {}
                }
        
        # 获取请求中的模型名称和文件类型
        model_name = request.model_name if request.model_name and request.model_name.strip() else None
        file_type = request.file_type
        
        print(f"处理发票提取请求: 文件路径={image_path}, 模型名称={model_name}, 文件类型={file_type}")
        
        # 步骤1：使用通用JSON提取获取初步结构和OCR文本
        extraction_result = extract_general_json_from_image(image_path, model_name)
        ocr_text = extraction_result.get("ocr_text", "")
        
        # 获取JSON数据，优先使用解析后的数据
        json_data = extraction_result.get("json_data", {})
        original_content = json_data.get("raw_content", "")
        
        # 如果存在已解析的JSON，使用它
        parsed_json = json_data.get("parsed_json", {}) if isinstance(json_data, dict) else {}
        
        # 步骤2：使用发票模板提示词映射转换为标准发票结构
        invoice_data = map_to_invoice_structure(ocr_text, model_name, file_type)
        
        # 步骤3：清理数据中的特殊符号
        cleaned_invoice_data = clean_invoice_data(invoice_data)
        
        # 保存原始型号值，用于比较是否有变化
        original_model = invoice_data.get('model', '')
        cleaned_model = cleaned_invoice_data.get('model', '')
        has_model_changes = original_model != cleaned_model and original_model and cleaned_model
        
        # 步骤4：验证发票数据
        validation_result = validate_invoice_numbers(cleaned_invoice_data)
        
        # 将验证结果添加到返回数据中
        cleaned_invoice_data['validation_result'] = validation_result
        
        # 检查是否有model字段被修正，如果有，更新到返回数据中
        if 'model' in validation_result.get('details', {}) and 'corrected' in validation_result['details']['model']:
            # 将修正后的model值更新到返回数据中
            corrected_model = validation_result['details']['model']['corrected']
            cleaned_invoice_data['model'] = corrected_model
            
            # 构建详细的修正信息
            extracted_model = validation_result['details']['model']['extracted']
            correction_details = []
            
            # 添加原始清理的变化信息
            if has_model_changes:
                correction_details.append(f"OCR识别值: {original_model}")
                correction_details.append(f"基本清理后: {cleaned_model}")
            
            # 添加验证阶段的修正信息
            correction_details.append(f"最终修正值: {corrected_model}")
            
            # 添加修正详情和警告信息
            if 'message' in validation_result['details']['model']:
                correction_details.append(validation_result['details']['model']['message'])
            
            # 添加修正说明
            cleaned_invoice_data['model_correction_info'] = "\n".join(correction_details)
        elif has_model_changes:
            # 如果只有清理阶段有变化，也记录下来
            cleaned_invoice_data['model_correction_info'] = f"OCR识别值: {original_model}，已修正为: {cleaned_model}"
        
        # 检查验证结果
        validation_status = validation_result.get('status', '')
        response_status = "success"
        response_message = f"{file_type}数据提取成功"
        
        if validation_status in ['has_errors', 'validation_error']:
            response_message += "，但存在验证问题，请查看验证结果"
        
        if has_model_changes or 'model' in validation_result.get('details', {}):
            response_message += "，规格型号字段存在自动修正，请检查"
        
        # 构建一个完整的原始JSON对象
        original_json_result = {
            "raw_content": original_content,
            "ocr_text": ocr_text
        }
        
        # 如果存在解析后的JSON，添加到返回结果中
        if parsed_json:
            original_json_result["parsed_json"] = parsed_json
        
        # 返回标准格式的响应
        return {
            "status": response_status,
            "data": cleaned_invoice_data,
            "original_json": original_json_result,
            "message": response_message
        }
    
    except json.JSONDecodeError as e:
        error_message = f"解析JSON失败: {str(e)}"
        print(error_message)
        traceback.print_exc()
        
        return {
            "status": "error",
            "message": error_message,
            "data": {},
            "original_json": {}
        }
    
    except openai.OpenAIError as e:
        error_message = f"调用OpenAI API出错: {str(e)}"
        print(error_message)
        traceback.print_exc()
        
        return {
            "status": "error",
            "message": error_message,
            "data": {},
            "original_json": {}
        }
            
    except Exception as e:
        error_traceback = traceback.format_exc()
        error_message = f"处理请求时出错: {str(e)}"
        print(error_message)
        print(error_traceback)
        
        return {
            "status": "error",
            "message": error_message,
            "data": {},
            "original_json": {}
        }
